﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

using Skewworks.Win.Motif;

namespace Motif
{
    public partial class frmMain : Form
    {

        #region Variables

        private string _target;
        private string _title;
        private bool _modified;
        private string _filename;

        private Hashtable _htControls;

        private IMotifPlugin[] _plugins;
        private IMotifPlugin _activePlugin;

        #endregion

        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            //NewGlideProject();
            _filename = string.Empty;
            LoadPlugins();
        }

        void LoadPlugins()
        {
            string[] sFiles = Directory.GetFiles(Path.GetDirectoryName(Application.ExecutablePath) + "\\Plugins\\");
            bool bFound;

            for (int i = 0; i < sFiles.Length; i++)
            {
                if (Path.GetExtension(sFiles[i]).ToLower() == ".dll")
                {
                    bFound = false;
                    Assembly plg = Assembly.LoadFile(sFiles[i]);
                    Type[] t = plg.GetTypes();
                    for (int j = 0; j < t.Length; j++)
                    {
                        Type[] tt = t[j].GetInterfaces();
                        for (int k = 0; k < tt.Length; k++)
                        {
                            if (tt[k].FullName == "Skewworks.Win.Motif.IMotifPlugin")
                            {
                                LoadPlugin(plg, t[j].FullName);
                                bFound = true;
                                break;
                            }
                        }
                        if (bFound)
                            break;
                    }
                }
            }
        }

        void LoadPlugin(Assembly asm, string fullname)
        {
            IMotifPlugin plg = (IMotifPlugin)asm.CreateInstance(fullname);
            if (plg != null)
            {
                // Add to plugin array
                if (_plugins == null)
                    _plugins = new IMotifPlugin[] { plg };
                else
                {
                    IMotifPlugin[] tmp = new IMotifPlugin[_plugins.Length + 1];
                    Array.Copy(_plugins, tmp, _plugins.Length);
                    tmp[tmp.Length - 1] = plg;
                    _plugins = tmp;
                }

                // Create "New" menu item
                ToolStripMenuItem mnu = new ToolStripMenuItem(plg.ProjectTypeName + " Project");
                mnu.Click += (object sender, EventArgs e) => LoadPluginProject(_plugins.Length - 1);

                // Add to File New
                fNew.DropDownItems.Add(mnu);
                
            }
        }

        void LoadPluginProject(int index)
        {
            _activePlugin = _plugins[index];
            _title = "Untitled";
            _target = _activePlugin.ProjectTypeName;
            _filename = string.Empty;
            UpdateTitlebar();

            // Clear controls
            pnlPreview.Controls.Clear();
            _htControls = new Hashtable();

            // Update Image List
            ilGlide.Images.Clear();
            ilGlide.Images.AddRange(_activePlugin.ControlListImages);

            // Add Controls
            lstControls.Items.Clear();
            lstControls.Items.AddRange(_activePlugin.ControlListNames);

            // Create Window
            IEmbeddedControl ec = _activePlugin.DefaultWindowControl;
            pnlPreview.Controls.Add((Control)ec);
            _htControls.Add(ec.Name, ec);
            ((Control)ec).Click += (object sender2, EventArgs e2) => ControlClick((Control)ec);

            // Update Properties
            cboControls.Items.Add(ec.Name);
            cboControls.SelectedIndex = 0;

            fSave.Enabled = true;
        }

        void UpdateTitlebar()
        {
            string stitle = _title + ((_modified) ? "*" : string.Empty);
            this.Text = stitle + "(" + _target + " Project) - Motif";
        }

        private void cboControls_SelectedIndexChanged(object sender, EventArgs e)
        {
            pg1.SelectedObject = null;

            if (cboControls.SelectedIndex == -1)
                return;

            object ctrl = _htControls[cboControls.Items[cboControls.SelectedIndex].ToString()];
            if (ctrl == null)
                return;

            pg1.SelectedObject = ((IEmbeddedControl)ctrl).Settings;
        }

        private void pnlPreview_Click(object sender, EventArgs e)
        {
            cboControls.SelectedIndex = -1;
        }

        private void pnlProperties_Resize(object sender, EventArgs e)
        {
            pg1.Height = pnlProperties.Height - 72;
            lstControls.Height = pnlProperties.Height - 44;
            
        }

        private void lstControls_Click(object sender, EventArgs e)
        {
            // Get Control
            Control ec = (Control)_activePlugin.ControlByTypeName(_activePlugin.ControlListNames[lstControls.SelectedIndex]);

            if (ec == null)
            {
                MessageBox.Show("Failed to retrieve control type '" + _activePlugin.ControlListNames[lstControls.SelectedIndex] + "' from plugin!", _activePlugin.ProjectTypeName);
                return;
            }

            // Setup control
            string sName = GetFirstName(ec.Name);
            ec.Text = sName;
            ec.Name = sName;
            ec.Click += (object sender2, EventArgs e2) => ControlClick(ec);

            // Add Control
            pnlPreview.Controls[0].Controls.Add(ec);
            ec.BringToFront();
            _htControls.Add(ec.Name, ec);

            // Add to list
            cboControls.Items.Add(sName);
            cboControls.SelectedIndex = cboControls.Items.Count - 1;

            eRemove.Enabled = true;
            epHCenter.Enabled = true;
            epVCenter.Enabled = true;
        }

        private void ControlClick(Control e)
        {
            if (!e.Focused)
                e.Focus();
            for (int i = 0; i < cboControls.Items.Count; i++)
            {
                if (cboControls.Items[i].ToString() == e.Name)
                {
                    cboControls.SelectedIndex = i;
                    return;
                }
            }
        }

        private void lstControls_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Bounds.Width == 0 || e.Bounds.Height == 0)
                return;

            Brush bsh = new LinearGradientBrush(e.Bounds, Color.FromArgb(226, 226, 226), Color.FromArgb(202, 202, 202), 90F);
            Brush bshText = Brushes.Black;

            if ((e.State & DrawItemState.Focus) == DrawItemState.Focus)
            {
                bsh = new LinearGradientBrush(e.Bounds, Color.FromArgb(0, 241, 210), Color.FromArgb(0, 161, 241), 90F);
                bshText = Brushes.White;
            }

            e.Graphics.FillRectangle(bsh, e.Bounds);
            e.Graphics.DrawImageUnscaled(ilGlide.Images[e.Index], e.Bounds.X + 2, e.Bounds.Y + 2, 28, 28);
            e.Graphics.DrawString(lstControls.Items[e.Index].ToString(), e.Font, bshText, new Point(e.Bounds.X + 34, e.Bounds.Y + 16 - (e.Font.Height / 2)));
        }

        private void lstControls_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void lstControls_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            e.ItemHeight = 32;
        }

        private string GetFirstName(string name)
        {
            if (_htControls[name] == null)
                return name;

            int i = 1;
            while (true)
            {
                if (_htControls[name + i] == null)
                    return name + i;
                i++;
            }
        }

        private void fSave_Click(object sender, EventArgs e)
        {
            if (_filename == string.Empty)
            {
                SFD.Title = "Save " + _activePlugin.ProjectTypeName + " Project";
                if (SFD.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                    return;
                _filename = SFD.FileName;
            }
                
            _activePlugin.SaveProject(_filename, (IEmbeddedControl)pnlPreview.Controls[0]);
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OFD.Title = "Open Project";
            if (OFD.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                return;

            FileStream fs = new FileStream(OFD.FileName, FileMode.Open, FileAccess.Read);
            byte[] b, b2;
            string s;
            for (int i = 0; i < _plugins.Length; i++)
            {
                for (int ii = 0; ii < _plugins[i].AcceptedHeaders.Length; ii++)
                {
                    fs.Seek(0, SeekOrigin.Begin);
                    if (_plugins[i].AcceptedHeaders[ii].IsString)
                    {
                        s = (string)_plugins[i].AcceptedHeaders[ii].HeaderValue;
                        b = new byte[s.Length];
                        fs.Read(b, 0, b.Length);
                        if (new string(Encoding.UTF8.GetChars(b)) == s)
                        {
                            fs.Close();
                            LoadProjectFromFile(OFD.FileName, i, ii);
                            return;
                        }
                    }
                    else
                    {
                        b2 = (byte[])_plugins[i].AcceptedHeaders[ii].HeaderValue;
                        b = new byte[b2.Length];
                        fs.Read(b, 0, b.Length);
                        if (b2 == b)
                        {
                            fs.Close();
                            LoadProjectFromFile(OFD.FileName, i, ii);
                            return;
                        }
                    }
                }
            }

        }

        private void LoadProjectFromFile(string filename, int pluginIndex, int headerIndex)
        {
            LoadPluginProject(pluginIndex);
            _activePlugin.OpenProject(filename, headerIndex, (IEmbeddedControl)pnlPreview.Controls[0]);

            for (int i = 0; i < pnlPreview.Controls[0].Controls.Count; i++)
            {
                Control ec = pnlPreview.Controls[0].Controls[i];
                //pnlPreview.Controls[0].Controls[i].BringToFront();
               ec.Click += (object sender2, EventArgs e2) => ControlClick(ec);
                _htControls.Add(ec.Name, pnlPreview.Controls[0].Controls[i]);
                cboControls.Items.Add(ec.Name);
            }

            _title = Path.GetFileName(filename);
            _target = _activePlugin.ProjectTypeName;
            _filename = filename;
            UpdateTitlebar();
            eRemove.Enabled = pnlPreview.Controls[0].Controls.Count > 0;
            epHCenter.Enabled = eRemove.Enabled;
            epVCenter.Enabled = eRemove.Enabled;
        }

        private void eRemove_Click(object sender, EventArgs e)
        {
            int index = cboControls.SelectedIndex;
            if (index == -1)
                return;

            object ctrl = _htControls[cboControls.Items[cboControls.SelectedIndex].ToString()];
            if (ctrl == null)
                return;

            pnlPreview.Controls[0].Controls.Remove((Control)ctrl);
            _htControls.Remove(cboControls.Items[cboControls.SelectedIndex].ToString());
            cboControls.Items.RemoveAt(index);

            eRemove.Enabled = pnlPreview.Controls[0].Controls.Count > 0;
            epHCenter.Enabled = eRemove.Enabled;
            epVCenter.Enabled = eRemove.Enabled;
        }

        private void epHCenter_Click(object sender, EventArgs e)
        {
            Control win = pnlPreview.Controls[0];
            Control ctrl = (Control)_htControls[cboControls.Items[cboControls.SelectedIndex].ToString()];
            ctrl.Left = win.Width / 2 - ctrl.Width / 2;
        }

        private void epVCenter_Click(object sender, EventArgs e)
        {
            Control win = pnlPreview.Controls[0];
            Control ctrl = (Control)_htControls[cboControls.Items[cboControls.SelectedIndex].ToString()];
            ctrl.Top = win.Height / 2 - ctrl.Height / 2;
        }

    }
}
